import axios from "axios";
import CryptoJS from "crypto-js";
import {v4 as uuid} from "uuid";
import {message} from "@/utils/message";
import {authorization, getToken} from "@/utils/auth";

import storm from "@/utils/storm";

import {Request, Response} from "@/api";
import {FileData, FileOption, FileParam} from "@/api/file";
import {radixConvert} from "@/utils/storm/security";

const fileService = storm.app + "/file";
export const uploadUri = fileService + "/api/upload";
export const downloadUri = fileService + "/api/download";
export const viewUri = fileService + "/api/view";

export async function upload(
  file: File,
  fileOption: FileOption
): Promise<Response<FileData>> {
  const token = getToken();
  const trace = uuid().replaceAll("-", "");
  const time = new Date().toUTCString();
  const hash = await sha256(file);
  const xHash = storm.encrypt(hash);
  return await axios
    .post(
      uploadUri,
      {
        file,
        mark: fileOption.mark,
        time: fileOption.time
      },
      {
        headers: {
          "Content-Type": "multipart/form-data",
          Authorization: authorization(token),
          "X-Hash": xHash,
          "X-Client": storm.CLIENT_ID,
          "X-Security": "AES",
          "X-Time": time,
          "X-Trace": trace
        }
      }
    )
    .then(({data}) => {
      const code = data.code;
      const cipher = data.data;
      const plains = storm.decrypt(cipher);
      const fileData: FileData = JSON.parse(plains);
      console.log("data", fileData);
      const response: Response<FileData> = {
        code,
        message: data.message,
        data: fileData
      };
      if (code === "000000") {
        message("上传成功", {type: "success"});
        return response;
      } else {
        message(data.message, {type: "error"});
        return Promise.reject(response);
      }
    })
    .catch(error => {
      console.error(error);
      return Promise.reject(error);
    });
}

export async function download(request: Request<FileParam>): Promise<void> {
  const token = getToken();
  const trace = uuid().replaceAll("-", "");
  const time = new Date().toUTCString();
  const param = request.param;
  console.log("param", param);
  const plains = JSON.stringify(param);
  const cipher = storm.encrypt(plains);
  await axios
    .post(
      downloadUri,
      {
        param: cipher
      },
      {
        headers: {
          "Content-Type": "application/json",
          Authorization: authorization(token),
          "X-Client": storm.CLIENT_ID,
          "X-Security": "AES",
          "X-Time": time,
          "X-Trace": trace
        },
        responseType: "blob"
      }
    )
    .then(response => {
      output(response);
    })
    .catch(error => {
      console.error(error);
      return Promise.reject(error);
    });
}

/**
 * 下载 response blob
 * @param response
 */
export function output(response: any): void {
  const disposition = response.headers.get("content-disposition");
  console.debug(disposition);
  if (!disposition) {
    throw new Error();
  }
  const dis = disposition.split(";");
  let filename: string;
  for (let d of dis) {
    d = d.trim();
    if (d.startsWith("filename=")) {
      filename = d;
    }
  }
  if (!filename) {
    throw new Error();
  }
  const fn = filename.split("=");
  let name = fn[1];
  if (name.startsWith('"') && name.endsWith('"')) {
    name = name.substring(1, name.length - 1);
  }
  name = decodeURI(name);
  const blob = new Blob([response.data]);
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement("a");
  a.style.display = "none";
  a.href = url;
  a.download = name;
  a.click();
  window.URL.revokeObjectURL(url);
  a.remove();
}

export function fetch(name: string, url: string): void {
  const a = document.createElement("a");
  a.style.display = "none";
  a.href = url;
  a.target = "_blank";
  a.download = name;
  a.click();
  window.URL.revokeObjectURL(url);
  a.remove();
}

export function sha256(file: File): Promise<string> {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = function (e) {
      const data = e.target?.result;
      if (!data) {
        reject();
        return;
      }
      // @ts-ignore
      const wordArray = CryptoJS.lib.WordArray.create(data);
      const hash = CryptoJS.SHA256(wordArray);
      resolve(hash.toString());
    };
    reader.onerror = function (e) {
      reject(e);
    };
    reader.readAsArrayBuffer(file);
  });
}

export function url(param: FileParam) {
  if (!param || (!param.id && !param.code)) {
    return "";
  }
  let id: string = param.id;
  let code: string = param.code;
  if (id && !code) {
    code = radixConvert(id, 10, 62) as string;
  } else if (!id && code) {
    id = radixConvert(code, 62, 10) as string;
  } else {
    const c = radixConvert(id, 10, 62) as string;
    if (c !== code) {
      console.error("id and code not match");
      return "";
    }
  }
  return viewUri + "?" + "id=" + id + "&" + "code=" + code;
}
